//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __ELASTOS_RWLOCK_H__
#define __ELASTOS_RWLOCK_H__

//
// ReaderUndoOperation
//
class Thread;
class DzReaderWriterLock;
typedef class DzReaderWriterLock RWLock;

class ReaderUndoOperation : public DLinkNode
{
public:
    void Initialize(Thread *pThread, RWLock *pRWLock);
    void Undo(Thread *pThread);

public:
    Thread  *m_pThread;
    RWLock  *m_pRWLock;
    bool_t  m_bUndoOwner;
};

//
// ReaderWriterLock
//
class DzReaderWriterLock : public UndoOperation
{
    friend class ReaderUndoOperation;
    friend class PendingReadUndoOperation;
    friend class PendingWriteUndoOperation;

public:
    void IsReaderLockHeld(Boolean *pIsHeld);
    void IsWriterLockHeld(Boolean *pIsHeld);

    void ReaderUninterruptibleLock();
    void ReaderLock(WaitResult *pResult);

    void ReaderTryUninterruptibleLock(uint_t ticks, WaitResult *pResult);
    void ReaderTryLock(uint_t ticks, WaitResult *pResult);

    void ReaderUnlock();

    void WriterUninterruptibleLock();
    void WriterLock(WaitResult *pResult);

    void WriterTryUninterruptibleLock(uint_t ticks, WaitResult *pResult);
    void WriterTryLock(uint_t ticks, WaitResult *pResult);

    void WriterUnlock();

    void UninterruptibleUpgradeToWriter();
    void UpgradeToWriter(WaitResult *pResult);

    void TryUninterruptibleUpgradeToWriter(uint_t ticks, WaitResult *pResult);
    void TryUpgradeToWriter(uint_t ticks, WaitResult *pResult);

    void DowngradeFromWriter();

    virtual void Undo(Thread *pThread);

public:
    DzReaderWriterLock()
    {
        m_nNumberOfActiveReaders = 0;
        m_uNumberOfPendingReads  = 0;
        m_uNumberOfPendingWrites = 0;

        m_pUndoOperationOwner = NULL;
        m_readerUndoOperationList.Initialize();
    }

    virtual ~DzReaderWriterLock();

private:
    void AddWriterUndoOperation();
    void RemoveWriterUndoOperation();

private:
    int             m_nNumberOfActiveReaders;
    uint_t          m_uNumberOfPendingReads;
    uint_t          m_uNumberOfPendingWrites;
    DzMutex         m_lock;
    DzCondition     m_canRead;
    DzCondition     m_canWrite;

    Thread          *m_pUndoOperationOwner;
    bool_t          m_bUndoOwner;
    DLinkNode       m_readerUndoOperationList;
};

#endif //__ELASTOS_RWLOCK_H__
